#include "ccalmanager.h"

#include "cdbcalendar.h"
#include "cfilecalendar.h"

#include <buola/io/cfile.h>
#include <buola/io/cfolder.h>
#include <buola/io/filesystem.h>

#include "sql_commands.h"
#include "sql_bind.h"

namespace buola { namespace bcal {

CCalManager::CCalManager()
    :   mCurrent(nullptr)
{
    mStockColors.push_back(img::CColor(0.15,0.33,0.88));
    mStockColors.push_back(img::CColor(0.21,0.64,0.08));
    mStockColors.push_back(img::CColor(0.92,0.00,0.13));
    mStockColors.push_back(img::CColor(L"SteelBlue"));
    mStockColors.push_back(img::CColor(L"MediumVioletRed"));
    mStockColors.push_back(img::CColor(L"Gold"));
    mStockColors.push_back(img::CColor(L"LightSeaGreen"));
    mStockColors.push_back(img::CColor(L"Sienna"));
    mStockColors.push_back(img::CColor(L"RosyBrown"));

    InitDB();
}

CCalManager::~CCalManager()
{
}

void CCalManager::InitDB()
{
    io::CURI lURI=io::get_home()/".buola"/"bcal"/"calendar.db";

    bool lExisted=io::exists(lURI);

    if(!lExisted)
    {
        io::mkdir(lURI.GetParent(),true);
    }

    mDB.Create("sqlite");
    mDB.SetURI(lURI);
    mDB.Connect();

    mDB.Exec(sPragmas);

    if(!lExisted)
    {
        mDB.Exec(sCreateDataTables);
    }

    PrepareQueries();

    if(lExisted)
    {
        CDBQuery &lQ=mQueries.mGetCalendars;
        lQ.Exec();
        
        while(lQ.NextRow())
        {
            AddCalendar(lQ.ColumnInteger(1),lQ.ColumnInteger(0));
        }
    }

    if(mCalendars.empty())
    {
        NewLocalCalendar(L"Home");
        NewLocalCalendar(L"Work");
    }

}

void CCalManager::PrepareQueries()
{
    mQueries.mInsertCalendar.Create(mDB,sInsertCalendar);
    mQueries.mInsertEvent.Create(mDB,sInsertEvent);
    mQueries.mGetEventsBetween.Create(mDB,sGetEventsBetween);
    mQueries.mGetCalendars.Create(mDB,sGetCalendars);
    mQueries.mGetCalendar.Create(mDB,sGetCalendar);
}

CCalendar *CCalManager::NewLocalCalendar(const std::wstring &pName)
{
    CDBQueryRun lQ(mQueries.mInsertCalendar);
    
    lQ.Bind(BIND_INSERT_CALENDAR_NAME,pName);
    lQ.Bind(BIND_INSERT_CALENDAR_TYPE,(int)CCalendar::TYPE_LOCAL);
    lQ.Bind(BIND_INSERT_CALENDAR_COLOR,GetStockColor().RGBA());
    lQ.Exec();

    return AddCalendar(CCalendar::TYPE_LOCAL,lQ.GetLastInsertID());
}

CCalendar *CCalManager::OpenFileCalendar(const io::CURI &pURI)
{
    io::CURI lURI=pURI;
    lURI.MakeAbsolute(io::get_cwd());

    CDBQueryRun lQ(mQueries.mInsertCalendar);
    
    lQ.Bind(BIND_INSERT_CALENDAR_NAME,lURI.Name());
    lQ.Bind(BIND_INSERT_CALENDAR_TYPE,(int)CCalendar::TYPE_FILE);
    lQ.Bind(BIND_INSERT_CALENDAR_COLOR,GetStockColor().RGBA());
    lQ.Bind(BIND_INSERT_CALENDAR_URL,lURI.ToString());
    lQ.Exec();

    return AddCalendar(CCalendar::TYPE_FILE,lQ.GetLastInsertID());
}

CCalendar *CCalManager::AddCalendar(int pType,int pID)
{
    CCalendar *lCalendar;

    if(pType==CCalendar::TYPE_LOCAL)
    {
        lCalendar=new CDBCalendar(this,pID);
    }
    else if(pType==CCalendar::TYPE_FILE)
    {
        lCalendar=new CFileCalendar(this,pID);
    }
    else
    {
        msg_warn() << "unknown calendar type\n";
        return nullptr;
    }

    mCalendars.push_back(lCalendar);

    if(!mCurrent)
        mCurrent=lCalendar;

    sCalendarAdded(lCalendar);

    return lCalendar;
}

img::CColor CCalManager::GetStockColor()
{
    return mStockColors[mCalendars.size()];
}

/*namespace buola*/ } /*namespace bcal*/ }
